package org.dromara.lessor.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.dromara.admin.domain.ContractBill;
import org.dromara.admin.domain.GeneralConfig;
import org.dromara.admin.domain.Order;
import org.dromara.admin.domain.UserDetail;
import org.dromara.admin.domain.bo.OrderBo;
import org.dromara.admin.domain.vo.GeneralConfigVo;
import org.dromara.admin.domain.vo.OrderVo;
import org.dromara.admin.domain.vo.UserDetailVo;
import org.dromara.admin.enums.AuditStatus;
import org.dromara.admin.enums.BillType;
import org.dromara.admin.enums.OrderStatus;
import org.dromara.admin.enums.SigningStatus;
import org.dromara.admin.service.IGeneralConfigService;
import org.dromara.admin.service.IOrderService;
import org.dromara.admin.service.IUserDetailService;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysUser;
import org.springframework.stereotype.Service;
import org.dromara.lessor.domain.bo.HouseBo;
import org.dromara.lessor.domain.vo.HouseVo;
import org.dromara.lessor.domain.House;
import org.dromara.lessor.mapper.HouseMapper;
import org.dromara.lessor.service.IHouseService;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.stream.Collectors;

import static com.baomidou.mybatisplus.extension.toolkit.Db.updateById;

/**
 * 房源信息Service业务层处理
 *
 * @author Lion Li
 * @date 2025-09-01
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class HouseServiceImpl implements IHouseService {

    private final HouseMapper baseMapper;
    private final IOrderService orderService;
    private final IUserDetailService userDetailService;
    private final IGeneralConfigService iGeneralConfigService;

    /**
     * 查询房源信息
     *
     * @param id 主键
     * @return 房源信息
     */
    @Override
    public HouseVo queryById(Long id) {
        MPJLambdaWrapper<House> wrapper = new MPJLambdaWrapper<House>()
            .selectAll(House.class)
            .selectAssociation(GeneralConfig.class, HouseVo::getGeneralConfig)
            .select(SysUser::getNickName, SysUser::getPhonenumber)
            .select(UserDetail::getAvatar)
            .leftJoin(GeneralConfig.class, GeneralConfig::getId, House::getHouseLayoutId)
            .leftJoin(SysUser.class, SysUser::getUserId, House::getLessorId)
            .leftJoin(UserDetail.class, UserDetail::getUserId, House::getLessorId)
            .eq(House::getId, id);
        HouseVo houseVo = baseMapper.selectJoinOne(HouseVo.class, wrapper);
        if (BeanUtil.isEmpty(houseVo)) {
            throw new ServiceException("房源信息不存在！");
        }
        if (StringUtils.isNotEmpty(houseVo.getElectricalIds())) {
            // 分割字符串并转换为Long类型的List，处理各种边缘情况
            List<Long> longList = Arrays.stream(houseVo.getElectricalIds().split(","))
                .map(String::trim)  // 去除每个元素的前后空格
                .filter(StringUtils::isNotEmpty)  // 过滤空字符串元素（如",,123"分割后产生的空值）
                .map(idStr -> {
                    try {
                        return Long.parseLong(idStr);
                    } catch (NumberFormatException e) {
                        // 处理无效格式的ID，这里选择抛异常，确保数据有效性
                        throw new IllegalArgumentException("无效的ID格式: " + idStr, e);
                        // 如果需要忽略无效ID，可改为:
                        // log.warn("忽略无效ID: {}", idStr);
                        // return null;
                    }
                })
                // .filter(Objects::nonNull)  // 如果上面选择忽略无效ID，则启用此过滤
                .collect(Collectors.toList());

            // 只有当列表非空时才调用服务，避免无效调用
            if (!longList.isEmpty()) {
                List<GeneralConfigVo> generalConfigList = iGeneralConfigService.getGeneralConfigIds(longList);
                houseVo.setElectricalList(generalConfigList);
            } else {
                // 当所有ID都无效或为空时，设置为空列表（或null，根据业务需求）
                houseVo.setElectricalList(new ArrayList<>());
            }
        } else {
            // 当electricalIds为空时，明确设置为一个空列表（或null）
            houseVo.setElectricalList(new ArrayList<>());
        }
        return houseVo;
    }

    /**
     * 分页查询房源信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 房源信息分页列表
     */
    @Override
    public TableDataInfo<HouseVo> queryPageList(HouseBo bo, PageQuery pageQuery) {
        // 使用MPJBaseMapper进行联表查询house表、GeneralConfig表，
        MPJLambdaWrapper<House> wrapper = getHouseMPJLambdaWrapper(bo);
        Page<HouseVo> page = baseMapper.selectJoinPage(pageQuery.build(), HouseVo.class, wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 分页查询管理查询二审租客房源订单
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return
     */
    @Override
    public TableDataInfo<HouseVo> twoInstanceList(HouseBo bo, PageQuery pageQuery) {
        MPJLambdaWrapper<House> wrapper = new MPJLambdaWrapper<House>()
            .selectAll(House.class) // 订单表字段
            .selectAssociation(Order.class, HouseVo::getOrder)
            .selectAssociation(GeneralConfig.class, HouseVo::getGeneralConfig)
            .selectAssociation("tu", SysUser.class, HouseVo::getTenantUser)
            .selectAssociation("lu", SysUser.class, HouseVo::getLessorUser)
            .selectAssociation("cu", SysUser.class, HouseVo::getCapitalUser)
            .leftJoin(Order.class, Order::getHouseId, House::getId)
            .leftJoin(GeneralConfig.class, GeneralConfig::getId, House::getHouseLayoutId)//关联GeneralConfig表
            // 租客信息 join
            .leftJoin(SysUser.class, "tu", on -> on.eq(SysUser::getUserId, Order::getUserId))
            // 出租方信息 join
            .leftJoin(SysUser.class, "lu", on -> on.eq(SysUser::getUserId, Order::getLessorUserId))
            // 资方代理信息 join
            .leftJoin(SysUser.class, "cu", on -> on.eq(SysUser::getUserId, Order::getCapitalUserId))
            // 加一个条件，过滤掉没有订单的情况
            .isNotNull(Order::getId);
        Page<HouseVo> page = baseMapper.selectJoinPage(pageQuery.build(), HouseVo.class, wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 分页查询已出租的房源信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 房源信息分页列表
     */
    @Override
    public TableDataInfo<HouseVo> queryRentedList(HouseBo bo, PageQuery pageQuery) {
        // 使用MPJBaseMapper进行联表查询house表、GeneralConfig表、order表。
        MPJLambdaWrapper<House> wrapper = getHouseMPJLambdaWrapper(bo)
            .eq(Order::getOrderStatus, OrderStatus.EFFECTING.getCode());
        Page<HouseVo> page = baseMapper.selectJoinPage(pageQuery.build(), HouseVo.class, wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 联表查询 hr_general_config\SysUser\UserDetail\Order
     *
     * @param bo
     * @return
     */
    private static MPJLambdaWrapper<House> getHouseMPJLambdaWrapper(HouseBo bo) {
        return new MPJLambdaWrapper<House>()
            .selectAll(House.class)//查询house表全部字段
            .selectAssociation(Order.class, HouseVo::getOrder)
            .selectAssociation(GeneralConfig.class, HouseVo::getGeneralConfig)
            .select(SysUser::getNickName, SysUser::getPhonenumber)
            .select(UserDetail::getAvatar)
            .leftJoin(GeneralConfig.class, GeneralConfig::getId, House::getHouseLayoutId)//关联GeneralConfig表
            .leftJoin(Order.class, Order::getHouseId, House::getId)
            .leftJoin(SysUser.class, SysUser::getUserId, Order::getUserId)
            .leftJoin(UserDetail.class, UserDetail::getUserId, Order::getUserId)
            .eq(bo.getId() != null, House::getId, bo.getId())
            .eq(bo.getLessorId() != null, House::getLessorId, bo.getLessorId())
            .eq(bo.getSaleId() != null, House::getSaleId, bo.getSaleId())
            .eq(bo.getHouseLayoutId() != null, House::getHouseLayoutId, bo.getHouseLayoutId())
            .eq(StringUtils.isNotBlank(bo.getPropertyNumber()), House::getPropertyNumber, bo.getPropertyNumber())
            .eq(StringUtils.isNotBlank(bo.getHouseStatus()), House::getHouseStatus, bo.getHouseStatus())
            .eq(StringUtils.isNotBlank(bo.getIsLaunch()), House::getIsLaunch, bo.getIsLaunch())
            .like(StringUtils.isNotBlank(bo.getOwnerName()), House::getOwnerName, bo.getOwnerName())
            .eq(StringUtils.isNotBlank(bo.getIdCardNumber()), House::getIdCardNumber, bo.getIdCardNumber())
            .like(StringUtils.isNotBlank(bo.getProvince()), House::getProvince, bo.getProvince())
            .like(StringUtils.isNotBlank(bo.getCity()), House::getCity, bo.getCity())
            .like(StringUtils.isNotBlank(bo.getAddress()), House::getAddress, bo.getAddress())
            .eq(StringUtils.isNotBlank(bo.getRentalType()), House::getRentalType, bo.getRentalType())
            .like(StringUtils.isNotBlank(bo.getEstateName()), House::getEstateName, bo.getEstateName())
            .like(StringUtils.isNotBlank(bo.getHouseNumber()), House::getHouseNumber, bo.getHouseNumber())
            .eq(bo.getContractStartDate() != null, House::getContractStartDate, bo.getContractStartDate())
            .eq(bo.getContractEndDate() != null, House::getContractEndDate, bo.getContractEndDate())
            .eq(StringUtils.isNotBlank(bo.getContractStatus()), House::getContractStatus, bo.getContractStatus())
            .eq(bo.getRent() != null, House::getRent, bo.getRent())
            .eq(bo.getLeaseTerm() != null, House::getLeaseTerm, bo.getLeaseTerm())
            .eq(bo.getStartDate() != null, House::getStartDate, bo.getStartDate())
            .eq(StringUtils.isNotBlank(bo.getOrderMode()), House::getOrderMode, bo.getOrderMode())
            .orderByDesc(House::getCreateTime);
    }

    /**
     * 分页查询用户的房源信息列表
     *
     * @param bo
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<HouseVo> queryTenantPageList(HouseBo bo, PageQuery pageQuery) {
        // 使用MPJBaseMapper进行联表查询house表、GeneralConfig表，
        MPJLambdaWrapper<House> wrapper = getHouseMPJLambdaWrapper(bo);
        // 房源审核成功的，以及业务员未出租的
        wrapper.eq(House::getHouseStatus, AuditStatus.APPROVED)
            .eq(House::getIsLaunch, AuditStatus.Y.getCode())
            .isNull(House::getSaleId);
        Page<HouseVo> page = baseMapper.selectJoinPage(pageQuery.build(), HouseVo.class, wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 分页查询当前业务员的房源信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 房源信息分页列表
     */
    @Override
    public TableDataInfo<HouseVo> queryPageMyHouseList(HouseBo bo, PageQuery pageQuery, Long userId) {
        // 获取当前业务员ID
        if (userId == null) {
            throw new ServiceException("用户ID不能为空");
        }
        // 根据业务员id查询所属哪个出租方
        Long lessorId = userDetailService.queryById(userId).getLessorId();
        // 判断是否是业务员操作
        if (lessorId == null) {
            throw new ServiceException("当前登录用户不是业务员");
        }
        // 根据出租方id查询所有房源
        bo.setLessorId(lessorId);
        bo.setSaleId(userId);
        MPJLambdaWrapper<House> wrapper = getHouseMPJLambdaWrapper(bo);
        // 查询为出租的房源
        wrapper.or(s -> s.isNull(House::getSaleId));
        Page<HouseVo> result = baseMapper.selectJoinPage(pageQuery.build(), HouseVo.class, wrapper);
        return TableDataInfo.build(result);
    }

    /**
     * 业务员查询自己办理的房源订单
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @param userId    业务员ID
     * @return
     */
    @Override
    public TableDataInfo<HouseVo> queryPageMyOrderList(HouseBo bo, PageQuery pageQuery, Long userId) {
        if (userId == null) {
            throw new ServiceException("用户ID不能为空");
        }
        // 使用MPJBaseMapper进行联表查询house表、order表、contract_bill表，根据业务员ID，并且contract_bill表为租金账单
        MPJLambdaWrapper<House> wrapper = new MPJLambdaWrapper<House>()
            .selectAll(House.class)//查询house表全部字段
            .selectAssociation(Order.class, HouseVo::getOrder)
            .selectAssociation(GeneralConfig.class, HouseVo::getGeneralConfig)
            .leftJoin(Order.class, Order::getHouseId, House::getId)
            .leftJoin(GeneralConfig.class, GeneralConfig::getId, House::getHouseLayoutId)
//            .eq(ContractBill::getBillType, BillType.RENT)
            .eq(House::getSaleId, userId)
            .eq(StrUtil.isNotBlank(bo.getOrderStatus()), Order::getOrderStatus, bo.getOrderStatus());
        List<HouseVo> houseVoList = baseMapper.selectJoinList(HouseVo.class, wrapper);
        return TableDataInfo.build(houseVoList);
    }

    /**
     * 查询符合条件的房源信息列表
     *
     * @param bo 查询条件
     * @return 房源信息列表
     */
    @Override
    public List<HouseVo> queryList(HouseBo bo) {
        LambdaQueryWrapper<House> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<House> buildQueryWrapper(HouseBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<House> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(House::getCreateTime);
        lqw.eq(bo.getLessorId() != null, House::getLessorId, bo.getLessorId());
        lqw.eq(bo.getSaleId() != null, House::getSaleId, bo.getSaleId());
        lqw.eq(StringUtils.isNotBlank(bo.getPropertyNumber()), House::getPropertyNumber, bo.getPropertyNumber());
        lqw.eq(StringUtils.isNotBlank(bo.getHouseStatus()), House::getHouseStatus, bo.getHouseStatus());
        lqw.like(StringUtils.isNotBlank(bo.getOwnerName()), House::getOwnerName, bo.getOwnerName());
        lqw.eq(StringUtils.isNotBlank(bo.getIdCardNumber()), House::getIdCardNumber, bo.getIdCardNumber());
        lqw.like(StringUtils.isNotBlank(bo.getProvince()), House::getProvince, bo.getProvince());
        lqw.like(StringUtils.isNotBlank(bo.getCity()), House::getCity, bo.getCity());
        lqw.like(StringUtils.isNotBlank(bo.getAddress()), House::getAddress, bo.getAddress());
        lqw.eq(StringUtils.isNotBlank(bo.getRentalType()), House::getRentalType, bo.getRentalType());
        lqw.like(StringUtils.isNotBlank(bo.getEstateName()), House::getEstateName, bo.getEstateName());
        lqw.like(StringUtils.isNotBlank(bo.getHouseNumber()), House::getHouseNumber, bo.getHouseNumber());
        lqw.eq(bo.getContractStartDate() != null, House::getContractStartDate, bo.getContractStartDate());
        lqw.eq(bo.getContractEndDate() != null, House::getContractEndDate, bo.getContractEndDate());
        lqw.eq(StringUtils.isNotBlank(bo.getContractStatus()), House::getContractStatus, bo.getContractStatus());
        lqw.eq(bo.getRent() != null, House::getRent, bo.getRent());
        lqw.eq(bo.getLeaseTerm() != null, House::getLeaseTerm, bo.getLeaseTerm());
        lqw.eq(bo.getStartDate() != null, House::getStartDate, bo.getStartDate());
        lqw.eq(StringUtils.isNotBlank(bo.getOrderMode()), House::getOrderMode, bo.getOrderMode());
//        lqw.eq(StringUtils.isNotBlank(bo.getDeductionMode()), House::getDeductionMode, bo.getDeductionMode());
        lqw.like(StringUtils.isNotBlank(bo.getTenantPhone()), House::getTenantPhone, bo.getTenantPhone());
        return lqw;
    }

    /**
     * 新增房源信息
     *
     * @param bo 房源信息
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(HouseBo bo) {
        House add = MapstructUtils.convert(bo, House.class);
        validEntityBeforeSave(add);
        // 创建房源默认待审核状态
        add.setHouseStatus(AuditStatus.PENDING.getCode());
        // 如果有合同照片，合同审核状态也要设置
        if (StrUtil.isNotBlank(add.getContractPhoto())) {
            add.setContractStatus(AuditStatus.PENDING.getCode());
        }
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改房源信息
     *
     * @param bo 房源信息
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(HouseBo bo) {
        House update = MapstructUtils.convert(bo, House.class);
        // 查询房源数据库信息
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(House entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除房源信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 业务员办单
     *
     * @param houseBo
     * @return
     */
    @Override
    public String handleRent(HouseBo houseBo) {
        Long houseId = houseBo.getId();
        if (houseId == null) {
            throw new ServiceException("请选择要租的房源");
        }
        House house = baseMapper.selectById(houseId);
        if (BeanUtil.isEmpty(house)) {
            throw new ServiceException("房源不存在");
        }
        if (!AuditStatus.APPROVED.getCode().equals(house.getHouseStatus())) {
            throw new ServiceException("房源未通过审核或被驳回不可租");
        }
        // 查询该房源是不是自己进行出租的
        Long saleIdDB = house.getSaleId();
        // 当saleIdDB不为空时，才需判断
        if (saleIdDB != null) {
            if (!saleIdDB.equals(houseBo.getSaleId())) {
                throw new ServiceException("该房源已有业务员进行出租！");
            }
        }

        // 生成二维码base64
        String base64 = generateQrCodeBase64(house.getId());

        // 查询房源是否未出租 -> true未出租
        Boolean b = orderService.queryByHouseId(houseId);
        if (b) {
            Boolean updatedByBo = this.updateByBo(houseBo);
            if (!updatedByBo) {
                throw new ServiceException("业务员办单过程中，添加信息失败！");
            }
        }
        return base64;
    }

    /**
     * 根据房源ID生成二维码的Base64字符串
     *
     * @param id 业务ID
     * @return 可直接给前端使用的base64字符串 (data:image/png;base64,...)
     */
    public static String generateQrCodeBase64(Long id) {
        try {
            // 要生成的二维码内容
            String content = String.valueOf(id);

            // 生成二维码图片
            BufferedImage image = QrCodeUtil.generate(content, 300, 300);

            // 转成字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(image, ImgUtil.IMAGE_TYPE_JPEG, outputStream);

            // Base64编码
            String base64 = Base64.encode(outputStream.toByteArray());

            return "data:image/jpeg;base64," + base64;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 用户租房
     *
     * @param bo     房源
     * @param userId 用户id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean rentHouseByHouseId(OrderBo bo, Long userId) {
        // 判断用户是否登录
        if (userId == null) {
            throw new ServiceException("请登录");
        }
        // 获取房源ID
        Long houseId = bo.getHouseId();
        if (houseId == null) {
            throw new ServiceException("请选择要租的房源");
        }

        // 判断房源是否未出租
        Boolean b = orderService.queryByHouseId(houseId);
        if (!b) {
            throw new ServiceException("该房源已出租！");
        }
        // 查询用户信息
        UserDetailVo userDetail = userDetailService.queryById(userId);
        if (BeanUtil.isEmpty(userDetail) || StrUtil.isEmpty(userDetail.getIdentityCard())) {
            throw new ServiceException("用户信息不存在或身份证号码不完整！");
        }
        // 获取房源信息
        House house = baseMapper.selectById(houseId);
        if (BeanUtil.isEmpty(house)) {
            throw new ServiceException("房源信息不存在！");
        }
        if (!AuditStatus.APPROVED.getCode().equals(house.getHouseStatus())) {
            throw new ServiceException("房源未通过审核或被驳回不可租");
        }
        // 判断办理的房源是否是自己的
        if (!house.getTenantIdCardNumber().equals(userDetail.getIdentityCard())) {
            throw new ServiceException("办理的房源不是自己的，请核对！");
        }

        // 获取用户授权图片url
        String userAuthUrl = bo.getUserAuthUrl();
        // 用户扫码后创建订单信息order
        return orderService.createOrderByHouse(house, userId, userAuthUrl);
    }

    /**
     * 审核出租方发布的房源信息
     *
     * @param houseBo 房源业务对象
     * @return
     */
    @Override
    public Boolean handleLessorRent(HouseBo houseBo) {
        Long houseId = houseBo.getId();
        if (houseId == null) {
            throw new ServiceException("请选择要审核的房源!");
        }
        House house = baseMapper.selectById(houseId);
        if (BeanUtil.isEmpty(house)) {
            throw new ServiceException("房源信息不存在!");
        }
        // 校验合同状态
//        String contractStatus = house.getContractStatus();
//        if (StringUtils.isNotBlank(contractStatus) && AuditStatus.PENDING.getCode().equals(contractStatus)) {
//            // 有值并且不是 "通过" → 不允许审核
//            throw new ServiceException("合同的审核状态异常，不允许进行房屋审核!");
//        }
        if (!AuditStatus.PENDING.getCode().equals(house.getHouseStatus())) {
            throw new ServiceException("请选择待审核的房源");
        }
        if (StrUtil.isNotBlank(houseBo.getRemark())) {
            house.setRemark(houseBo.getRemark());
        }
        house.setHouseStatus(houseBo.getHouseStatus());
        // 同步更新合同状态
        house.setContractStatus(houseBo.getHouseStatus());
        return baseMapper.updateById(house) > 0;
    }

    /**
     * 后台管理员审核房屋合同
     *
     * @param houseBo 房源业务对象(含房源ID和审核的状态)
     * @return
     */
    @Override
    public Boolean handleContract(HouseBo houseBo) {
        // 根据房源id校验是否存在
        House house = baseMapper.selectById(houseBo.getId());
        if (BeanUtil.isEmpty(house)) {
            throw new ServiceException("房源ID传入错误，不存在该房源信息！");
        }
        // 只有待审核状态的合同才能审核
        if (!AuditStatus.PENDING.getCode().equals(house.getContractStatus())) {
            throw new ServiceException("请选择待审核状态的合同房源！");
        }
        // 存在根据传入审核状态更新合同状态
        house.setContractStatus(houseBo.getContractStatus());
        return baseMapper.updateById(house) > 0;
    }

    /**
     * 业务员办单后取消订单
     *
     * @param houseId 房源ID
     * @return
     */
    @Override
    public Boolean saleCancel(Long houseId) {
        if (houseId == null) {
            throw new ServiceException("房源id不能为空！");
        }
        House house = baseMapper.selectById(houseId);
        if (BeanUtil.isEmpty(house)) {
            throw new ServiceException("房源信息不存在！");
        }
        // 查询房源是否未出租-有订单产生
        Boolean b = orderService.queryByHouseId(houseId);
        if (!b) {
            throw new ServiceException("该房源已经出租，不能取消!");
        }
        // 重置业务员填充字段
        setAllFieldsToNull(house);
        return baseMapper.updateById(house) > 0;
    }

    public static void setAllFieldsToNull(House house) {
        house.setSaleId(null);
        house.setHousePhotos(null);
        house.setLeaseTerm(null);
        house.setStartDate(null);
        house.setOrderMode(null);
        house.setDeductionMode(null);
        house.setDeposit(null);
        house.setTenantIdCardFront(null);
        house.setTenantIdCardBack(null);
        house.setTenantIdCardNumber(null);
        house.setTenantPhone(null);
        house.setTenantContract(null);
        house.setTenantAlipayCredit(null);
        house.setLandlordPaymentVideo(null);
        house.setNonLandlordPayment(null);
        house.setLongTermPaymentProof(null);
        house.setRemark(null);
    }

    /**
     * 切换房源上架状态
     * @param id
     * @return
     */
    @Override
    public Boolean toggleLaunch(Long id) {
        // 查询房源
        House house = baseMapper.selectById(id);
        if (BeanUtil.isEmpty(house)) {
            throw new ServiceException("房源不存在！");
        }

        if (house.getSaleId() != null) {
            throw new ServiceException("该房源正在出租流程中！");
        }

        // 获取当前房源上架状态
        String currentStatus = house.getIsLaunch();

        if (AuditStatus.Y.getCode().equals(currentStatus)) {
            // 当前是上架 → 下架
            house.setIsLaunch(AuditStatus.N.getCode());
        } else {
            // 当前是下架 → 上架，必须审核通过
            if (!AuditStatus.APPROVED.getCode().equals(house.getHouseStatus())) {
                throw new ServiceException("房源未审核通过，不能上架");
            }
            house.setIsLaunch(AuditStatus.Y.getCode());
        }
        return baseMapper.updateById(house) > 0;
    }
}
